package com.ivanceras.server.services;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.ivanceras.server.dao.DAO_Ad_column;
import com.ivanceras.server.dao.DAO_Ad_field;
import com.ivanceras.server.dao.DAO_Ad_reference;
import com.ivanceras.server.dao.DAO_Ad_tab;
import com.ivanceras.server.dao.DAO_Ad_table;
import com.ivanceras.server.dao.DAO_Ad_window;
import com.ivanceras.server.db.DatabaseManager;
import com.ivanceras.server.util.CStringUtils;
import com.ivanceras.server.util.Configuration;
import com.ivanceras.server.util.DataTypeUtils;
import com.ivanceras.shared.db.DAO;
import com.ivanceras.shared.db.EntityManager;
import com.ivanceras.shared.db.Filter;
import com.ivanceras.shared.db.IModelDef;
import com.ivanceras.shared.db.Order;
import com.ivanceras.shared.exception.DatabaseException;

public class DataAPI {

	public static DAO_Ad_window[] retrieveWindowList(EntityManager em) throws DatabaseException{
		DAO[] daoList = em.getAll(new DAO_Ad_window(), new Order("name", false));
		DAO_Ad_window[] daoWindowList = DAO_Ad_window.cast(daoList);
		return daoWindowList;
	}
	public static DAO_Ad_tab[] retriveTabList(EntityManager em, DAO_Ad_window daoWindow) throws DatabaseException {
		DAO_Ad_tab[] tabList = null;
		tabList = DAO_Ad_tab.cast(em.getChildren(daoWindow, new DAO_Ad_tab(), new Order("seqno")));
		for(DAO_Ad_tab tab : tabList){
			DAO_Ad_table table = DAO_Ad_table.cast(em.getOne(new DAO_Ad_table(), new Filter("ad_table_id", Filter.EQUAL, tab.getAd_table_id())));
			tab.setAd_table(table);
			DAO_Ad_field[] fieldList = DAO_Ad_field.cast(em.getAll(new DAO_Ad_field(), new Order("seqno"), new Filter("ad_tab_id", Filter.EQUAL, tab.getAd_tab_id())));
//			System.err.println("tab: "+tab.getName());
			for(DAO_Ad_field field : fieldList){
//				System.out.println("field: "+field.getName());
				DAO_Ad_column column = DAO_Ad_column.cast(em.getOne(new DAO_Ad_column(), new Filter("ad_column_id", Filter.EQUAL, field.getAd_column_id())));
//				System.out.println("column: "+column);
				if( column!=null ){
					DAO_Ad_reference reference = DAO_Ad_reference.cast(em.getOne(new DAO_Ad_reference(), new Filter("ad_reference_id", Filter.EQUAL, column.getAd_reference_id())));
					column.setAd_reference(reference);
					field.setAd_column(column);
				}
			}
			tab.setAd_fieldList(fieldList);
		}
		return tabList;
	}


	public static DAO[] retrieveTableData(EntityManager em, DAO_Ad_table table, Integer page, 
			Integer itemPerPage, Order order, Filter filter) throws DatabaseException {

		String tableName = CStringUtils.capitalize(table.getTablename().toLowerCase());
		Order[] orders = null;
		if(order != null){
			orders = new Order[1];
			orders[0] = order;
		}

		Filter[] filters = null;
		if(filter != null){
			filters = new Filter[1];
			filters[0] = filter;
		}

		DAO[] daoList = em.getAll(tableName, orders, filters, page, itemPerPage, false);
		return daoList;
	}
	public static Boolean saveDao(EntityManager em, DAO[] daoList) throws DatabaseException{
		if(Configuration.dbType.equals(DatabaseManager.BIGTABLE)){
			return saveDao(em, daoList, false);
		}else{
			return saveDao(em, daoList, true);
		}
	}
	
	public static Boolean saveDao(EntityManager em, DAO[] daoList, Boolean createTable) throws DatabaseException{
		for(DAO dao : daoList){
			if(createTable){
				em.createModel(em.getModelDefinition(dao.getModelName()));
			}
			em.insert(dao);
		}
		return true;
	}


	public static void importDAO(EntityManager em, String httpurl) throws MalformedURLException, DatabaseException {
		DAO[] daoList = parseXml(em, httpurl);
		saveDaoList(em, daoList);
	}
	
	private static DAO[] parseXml(EntityManager em, String httpurl) throws MalformedURLException{
		
		URL url = new URL(httpurl);

		List<DAO> daoList = new ArrayList<DAO>();
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();

			Document dom = db.parse(url.openStream());
			Element root = dom.getDocumentElement();
			NodeList models = dom.getElementsByTagName("model");
			int totalModel = models.getLength();

			for(int i = 0; i < totalModel; i++){
				Node nmodel = models.item(i);
				if(nmodel.getNodeType() == Node.ELEMENT_NODE){
					String table = ((Element)nmodel).getAttribute("name");
					NodeList rowList = ((Element)nmodel).getElementsByTagName("row");
					int totalRows = rowList.getLength();
					String modelName = CStringUtils.capitalize(table);
					DAO daoModel = new DAO(modelName);
					IModelDef modeldef = null;
					try {
						modeldef = em.getModelDefinition(daoModel.getModelName());
					} catch (DatabaseException e) {
						e.printStackTrace();
					}
					String[] model_attributes = modeldef.getAttributes();
					String[] model_datatypes = modeldef.getDataTypes();

					for(int r = 0; r < totalRows; r++){
						Node row = rowList.item(r);
						if(row.getNodeType() == Node.ELEMENT_NODE){
							NodeList attributes = ((Element)row).getChildNodes();
							DAO dao = new DAO(CStringUtils.capitalize(table));
							int totalAttributes = attributes.getLength();
							for(int a = 0; a < totalAttributes; a++){
								Node attrib = attributes.item(a);
								if(attrib.getNodeType() == Node.ELEMENT_NODE){
									Node nvalue = attrib.getFirstChild();
									if(nvalue.getNodeType() == Node.CDATA_SECTION_NODE){
										String attribute = attrib.getNodeName();
										String s_value = nvalue.getNodeValue();
										String dataType = model_datatypes[indexOf(model_attributes, attribute)]; 
										Object o_value = DataTypeUtils.convertFromString(s_value, dataType);
										dao.set_Value(attribute, o_value);
									}
								}
							}
							daoList.add(dao);
						}
					}
				}
			}

		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch(SAXException se) {
			se.printStackTrace();
		}catch(IOException ioe) {
			ioe.printStackTrace();
		}
		return daoList.toArray(new DAO[daoList.size()]);
	}
	
	
	private static int indexOf(String[] attributes, String key){
		for(int i = 0; i < attributes.length; i++){
			if(key.equals(attributes[i])){
				return i;
			}
		}
		return -1;
	}
	
	private static void saveDaoList(EntityManager em, DAO[] daoList) throws DatabaseException{
		if(daoList != null & daoList.length > 0 ){
			System.out.println("Importing "+daoList.length+" from "+daoList[0].getModelName()+".. ");
		}
		for(int i = 0; i < daoList.length; i++){
			DAO dao = daoList[i];
			Object value = dao.get_Value("name");
			if(value != null){
				System.out.println("..."+value+"...");
			}
			em.insert(dao);
		}
	}

	public static HashMap<String, Integer> parseTableListXml(String xmlurl) throws MalformedURLException{
		
		URL url = new URL(xmlurl);

		HashMap<String, Integer> tableCountList = new HashMap<String, Integer>();
		
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();

			Document dom = db.parse(url.openStream());
			Element root = dom.getDocumentElement();
			NodeList models = dom.getElementsByTagName("model");
			int totalModel = models.getLength();

			for(int i = 0; i < totalModel; i++){
				Node nmodel = models.item(i);
				if(nmodel.getNodeType() == Node.ELEMENT_NODE){
					String table = ((Element)nmodel).getAttribute("name");
					Integer count = Integer.parseInt(((Element)nmodel).getAttribute("count"));
					tableCountList.put(table, count);
				}
			}

		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch(SAXException se) {
			se.printStackTrace();
		}catch(IOException ioe) {
			ioe.printStackTrace();
		}
		return tableCountList;
	}
}
